package com.fingard.util;

import com.fingard.FGBiz;
import jcifs.UniAddress;
import jcifs.smb.*;

import java.io.*;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

import com.fingard.diagnostics.LogHelper;
import com.fingard.text.StringHelper;

/**
 * Created by Lewis on 2017/12/11.
 * 操作共享目录公共类
 */
public class SmbFileUtil {
    /**
     * 方法说明：从远程共享目录下载文件
     *
     * @param localDir  本地临时路径
     * @param remoteDir 远程共享路径
     * @param pFileName 远程共享文件名
     * @return
     * @throws Exception
     */
    public static int smbDownload(String localDir, String remoteDir,
                                  String pFileName,StringBuilder pSb) throws Exception {
        InputStream in = null;
        OutputStream out = null;
        try {
        	String trgFilePath = StringHelper.trimEndFileSp(remoteDir)+"/" + pFileName;
            SmbFile remoteFile = new SmbFile(trgFilePath);
            if (!remoteFile.exists()) {
            	pSb.append("远程文件"+trgFilePath+"不存在");
                return 0;
            }

            File dir = new File(localDir);
            if (!dir.exists()) {
                dir.mkdirs();
            }

            String fileName = pFileName.substring(pFileName.lastIndexOf("\\") + 1, pFileName.length());
            File localFile = new File(StringHelper.trimEndFileSp(localDir)+File.separator + fileName);
            in = new BufferedInputStream(new SmbFileInputStream(remoteFile));

            out = new BufferedOutputStream(new FileOutputStream(localFile));
            byte[] buffer = new byte[1024];
            while (in.read(buffer) != -1) {
                out.write(buffer);
                buffer = new byte[1024];
            }
        } catch (Exception e) {
            e.printStackTrace();
            pSb.append(LogHelper.getStackTrace(e));
        } finally {
            try {
                if (null != out) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (null != in) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return 1;
    }

    //获取目录中的文件
    public static SmbFile[] getSmbFiles(String URL) throws Exception {
        SmbFile smbfile = new SmbFile(URL);
        SmbFile[] files;
        if (!smbfile.exists()) {
            throw new Exception("共享目录不存在");
        } else {
            files = smbfile.listFiles();

        }
        return files;
    }

    /**
     * 方法说明：上传文件到远程共享目录
     *
     * @param localDir  本地临时路径(A:/测试/测试.xls)
     * @param path      本地临时文件的前置路径(要在共享目录新增的文件夹路径)
     * @param removeDir 远程共享路径(smb://pub(用户名):fingard1!(密码)@10.60.44.98/数据库脚本/2.3.0/)
     * @return
     * @throws Exception 0成功/-1失败/1表示文件已存在共享目录无需重复上传
     */
    public static int smbUploading(String localDir, String path, String removeDir) throws Exception {
    	return smbUploading(localDir, path, removeDir, "");
    }
    public static int smbUploading(String pLocalFile, String pSubPath, String removeDir, String pUpFileName) throws Exception {
        OutputStream out = null;
        int retVal = 0;
        try {
            File dir = new File(pLocalFile);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            String upFileName = pUpFileName;
            if(StringHelper.isNullOrEmpty(upFileName)){
            	upFileName = dir.getName();
            }
            SmbFile remoteFile = null;
            if (!StringHelper.isNullOrEmpty(pSubPath)) {
                //远程路径判断文件文件路径是否合法
                remoteFile = new SmbFile(removeDir + pSubPath + upFileName);
            } else {
                remoteFile = new SmbFile(removeDir + upFileName);
            }
            if (!remoteFile.exists()) {
                if (!new SmbFile(remoteFile.getParent()).exists()) {
                    new SmbFile(remoteFile.getParent()).mkdirs();
                }
                remoteFile.connect();
                if (remoteFile.isDirectory()) {
                    retVal = -1;
                }

                // 向远程共享目录写入文件
                out = new BufferedOutputStream(new SmbFileOutputStream(remoteFile));
                out.write(toByteArray(dir));
            } else if (remoteFile.exists()) {
                retVal = 1;
            }
        } catch (UnknownHostException e) {
            retVal = -1;
            throw(e);
        } catch (MalformedURLException e) {
            retVal = -1;
            throw(e);
        } catch (SmbException e) {
            retVal = -1;
            throw(e);
        } catch (IOException e) {
            retVal = -1;
            throw(e);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    FGBiz.limitMsg.exception("smbUploading", e, pLocalFile, pSubPath, removeDir);
                }
            }
        }

        return retVal;
    }

    public static String getUploadType(){
        String uploadType="";
        if(!"false".equals(FGBiz.dspCenter.dspSet.receiptShareDir) && !"sftp".equals(FGBiz.dspCenter.dspSet.receiptShareDir)){
            if(FGBiz.dspCenter.dspSet.receiptShareDir.startsWith("smb:")){
                uploadType ="smb";
            }else if(FGBiz.dspCenter.dspSet.receiptShareDir.startsWith("localhost")){
                uploadType ="localhost";
            }else{
                uploadType = "MicroService";
            }
        }
        if(StringHelper.hasAnyChar(uploadType)){
            return uploadType;
        }else{
            return FGBiz.dspCenter.dspSet.receiptShareDir;
        }
    }

    public static int smbWrite(String p_remoteFilePath, String p_fileContent, String p_charset, StringBuilder p_sb) throws Exception {
        OutputStream out = null;
        int retVal = 0;
        try {
            SmbFile remoteFile = null;

            remoteFile = new SmbFile(p_remoteFilePath);

            if (!remoteFile.exists()) {
                if (!new SmbFile(remoteFile.getParent()).exists()) {
                    new SmbFile(remoteFile.getParent()).mkdirs();
                }
                remoteFile.connect();
                if (remoteFile.isDirectory()) {
                    retVal = -1;
                    p_sb.append("路径指定有误！");
                }

                // 向远程共享目录写入文件
                out = new BufferedOutputStream(new SmbFileOutputStream(remoteFile));
                out.write(p_fileContent.getBytes(p_charset));
            } else if (remoteFile.exists()) {
                retVal = 1;
                p_sb.append("指定文件已存在！");
            }
        } catch (UnknownHostException e) {
            retVal = -1;
            e.printStackTrace();
            p_sb.append(e.getMessage());
        } catch (MalformedURLException e) {
            retVal = -1;
            e.printStackTrace();
            p_sb.append(e.getMessage());
        } catch (SmbException e) {
            retVal = -1;
            e.printStackTrace();
            p_sb.append(e.getMessage());
        } catch (IOException e) {
            retVal = -1;
            e.printStackTrace();
            p_sb.append(e.getMessage());
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return retVal;
    }

    public static int smbWrite(String p_remoteFilePath, byte[] p_fileContent, StringBuilder p_sb) throws Exception {
        OutputStream out = null;
        int retVal = 0;
        try {
            SmbFile remoteFile = null;

            remoteFile = new SmbFile(p_remoteFilePath);

            if (!remoteFile.exists()) {
                if (!new SmbFile(remoteFile.getParent()).exists()) {
                    new SmbFile(remoteFile.getParent()).mkdirs();
                }
                remoteFile.connect();
                if (remoteFile.isDirectory()) {
                    retVal = -1;
                    p_sb.append("路径指定有误！");
                }

                // 向远程共享目录写入文件
                out = new BufferedOutputStream(new SmbFileOutputStream(remoteFile));
                out.write(p_fileContent);
            } else if (remoteFile.exists()) {
                retVal = 1;
                p_sb.append("指定文件已存在！");
            }
        } catch (UnknownHostException e) {
            retVal = -1;
            e.printStackTrace();
            p_sb.append(e.getMessage());
        } catch (MalformedURLException e) {
            retVal = -1;
            e.printStackTrace();
            p_sb.append(e.getMessage());
        } catch (SmbException e) {
            retVal = -1;
            e.printStackTrace();
            p_sb.append(e.getMessage());
        } catch (IOException e) {
            retVal = -1;
            e.printStackTrace();
            p_sb.append(e.getMessage());
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return retVal;
    }

    /**
     * Mapped File way MappedByteBuffer 可以在处理大文件时，提升性能
     *
     * @param file 文件
     * @return 字节数组
     * @throws IOException IO异常信息
     */
    public static byte[] toByteArray(File file) throws IOException {
        FileChannel fc = null;
        try {
            fc = new RandomAccessFile(file, "r").getChannel();
            MappedByteBuffer byteBuffer = fc.map(FileChannel.MapMode.READ_ONLY, 0,
                    fc.size()).load();
            byte[] result = new byte[(int) fc.size()];
            if (byteBuffer.remaining() > 0) {
                byteBuffer.get(result, 0, byteBuffer.remaining());
            }
            return result;
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            try {
                fc.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 方法说明：从远程共享目录下载文件（密码包含特殊字符）
     *
     * @param localDir  本地临时路径
     * @param remoteDir 远程共享路径
     * @param pFileName 远程共享文件名
     * @return
     * @throws Exception
     */
    public static int smbDownloadInChar(String localDir, String remoteDir,
                                        String pFileName,StringBuilder pSb) throws Exception {
        int index=remoteDir.indexOf("//")+2;
        int end=remoteDir.indexOf(":",index);
        String usename=remoteDir.substring(index,end);
        index=end+1;
        end=remoteDir.lastIndexOf("@");
        String password=remoteDir.substring(index,end);
        index=end+1;
        end=remoteDir.indexOf("/",end);
        String ip=remoteDir.substring(index,end);
        String remoteurl="smb://"+ip+"/"+remoteDir.substring(end+1);
        NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(ip, usename, password);

        InputStream in = null;
        OutputStream out = null;
        try {
            String trgFilePath = StringHelper.trimEndFileSp(remoteurl)+"/" + pFileName;
            SmbFile remoteFile = new SmbFile(trgFilePath,auth);
            if (!remoteFile.exists()) {
                pSb.append("远程文件"+trgFilePath+"不存在");
                return 0;
            }

            File dir = new File(localDir);
            if (!dir.exists()) {
                dir.mkdirs();
            }

            String fileName = pFileName.substring(pFileName.lastIndexOf("\\") + 1, pFileName.length());
            File localFile = new File(StringHelper.trimEndFileSp(localDir)+File.separator + fileName);
            in = new BufferedInputStream(new SmbFileInputStream(remoteFile));

            out = new BufferedOutputStream(new FileOutputStream(localFile));
            byte[] buffer = new byte[1024];
            while (in.read(buffer) != -1) {
                out.write(buffer);
                buffer = new byte[1024];
            }
        } catch (Exception e) {
            e.printStackTrace();
            pSb.append(LogHelper.getStackTrace(e));
        } finally {
            try {
                if (null != out) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (null != in) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return 1;
    }

    /**
     * 上传文件到远程共享目录（密码包含特殊字符）
     * @param localDir 本地临时路径(A:/测试/测试.xls)
     * @param path     本地临时文件的前置路径(要在共享目录新增的文件夹路径)
     * @param removeDir  远程共享路径(smb://pub(用户名):fingard1!(密码)@10.60.44.98/数据库脚本/2.3.0/)
     * @return
     * @throws Exception  0成功/-1失败/1表示文件已存在共享目录无需重复上传
     */
    public static int smbUploadingInChar(String localDir, String path, String removeDir) throws Exception {
        return smbUploadingInChar(localDir,path,removeDir,"");
    }

    /**
     * 方法说明：上传文件到远程共享目录（密码包含特殊字符）
     *
     * @param localDir  本地临时路径(A:/测试/测试.xls)
     * @param path      本地临时文件的前置路径(要在共享目录新增的文件夹路径)
     * @param removeDir 远程共享路径(smb://pub(用户名):fingard1!(密码)@10.60.44.98/数据库脚本/2.3.0/)
     * @param pUpFileName 文件名
     * @return
     * @throws Exception 0成功/-1失败/1表示文件已存在共享目录无需重复上传
     */
    public static int smbUploadingInChar(String localDir, String path, String removeDir, String pUpFileName) throws Exception {
        int index=removeDir.indexOf("//")+2;
        int end=removeDir.indexOf(":",index);
        String usename=removeDir.substring(index,end);
        index=end+1;
        end=removeDir.lastIndexOf("@");
        String password=removeDir.substring(index,end);
        index=end+1;
        end=removeDir.indexOf("/",end);
        String ip=removeDir.substring(index,end);
        String remoteurl="smb://"+ip+"/"+removeDir.substring(end+1);
        NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(ip, usename, password);

        OutputStream out = null;
        int retVal = 0;
        try {
            File dir = new File(localDir);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            String upFileName = pUpFileName;
            if(StringHelper.isNullOrEmpty(upFileName)){
                upFileName = dir.getName();
            }

            SmbFile remoteFile = null;
            if (!StringHelper.isNullOrEmpty(path)) {
                //远程路径判断文件文件路径是否合法
                remoteFile = new SmbFile(remoteurl + path + upFileName,auth);
            } else {
                remoteFile = new SmbFile(remoteurl + upFileName,auth);
            }
            if (!remoteFile.exists()) {
                if (!new SmbFile(remoteFile.getParent(),auth).exists()) {
                    new SmbFile(remoteFile.getParent(),auth).mkdirs();
                }
                remoteFile.connect();
                if (remoteFile.isDirectory()) {
                    retVal = -1;
                }

                // 向远程共享目录写入文件
                out = new BufferedOutputStream(new SmbFileOutputStream(remoteFile));
                out.write(toByteArray(dir));
            } else if (remoteFile.exists()) {
                retVal = 1;
            }
        } catch (UnknownHostException e) {
            retVal = -1;
            e.printStackTrace();
        } catch (MalformedURLException e) {
            retVal = -1;
            e.printStackTrace();
        } catch (SmbException e) {
            retVal = -1;
            e.printStackTrace();
        } catch (IOException e) {
            retVal = -1;
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return retVal;
    }

    /**
     * 方法说明：写入文件至远程共享目录（支持密码包含特殊字符）
     * @param removeDir 远程共享路径
     * @param p_fileName 远程共享文件名
     * @param p_fileContent 内容
     * @param p_sb 日志
     * @param charset 编码
     * @return
     */
    public static int smbWriteFile(String removeDir,String p_fileName,String p_fileContent,StringBuilder p_sb,String charset){
        int index=removeDir.indexOf("//")+2;
        int end=removeDir.indexOf(":",index);
        String usename=removeDir.substring(index,end);
        index=end+1;
        end=removeDir.lastIndexOf("@");
        String password=removeDir.substring(index,end);
        index=end+1;
        end=removeDir.indexOf("/",end);
        String ip=removeDir.substring(index,end);
        String remoteurl="smb://"+ip+"/"+removeDir.substring(end+1);
        NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(ip, usename, password);
        int retVal=0;
        OutputStream out = null;
        try {
            //远程路径判断文件文件路径是否合法
            SmbFile remoteFile = new SmbFile(remoteurl + p_fileName,auth);
            if (!remoteFile.exists()) {
                if (!new SmbFile(remoteFile.getParent(),auth).exists()) {
                    new SmbFile(remoteFile.getParent(),auth).mkdirs();
                }
                remoteFile.connect();
                if (remoteFile.isDirectory()) {
                    retVal = -1;
                    p_sb.append("指定路径有误！");
                }
                // 向远程共享目录写入文件
                out = new BufferedOutputStream(new SmbFileOutputStream(remoteFile));
                out.write(p_fileContent.getBytes(charset));
            } else if (remoteFile.exists()) {
                retVal = 1;
                p_sb.append("指定文件已存在！");
            }
        } catch (UnknownHostException e) {
            retVal = -1;
            e.printStackTrace();
            p_sb.append("内容写入异常："+e.getMessage());
        } catch (MalformedURLException e) {
            retVal = -1;
            e.printStackTrace();
            p_sb.append("内容写入异常："+e.getMessage());
        } catch (SmbException e) {
            retVal = -1;
            e.printStackTrace();
            p_sb.append("内容写入异常："+e.getMessage());
        } catch (IOException e) {
            retVal = -1;
            e.printStackTrace();
            p_sb.append("内容写入异常："+e.getMessage());
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    p_sb.append("IO流关闭异常："+e.getMessage());
                }
            }
        }
        return retVal;
    }

    /**
     * 方法说明：从远程共享目录读取文件（支持密码包含特殊字符）
     * @param remoteDir 远程共享路径
     * @param pFileName 远程共享文件名
     * @param pSb 日志
     * @param charset 编码
     * @return
     */
    public static String smbReadFileText(String remoteDir,String pFileName,StringBuilder pSb,String charset){
        String remoteFileText="";
        int index=remoteDir.indexOf("//")+2;
        int end=remoteDir.indexOf(":",index);
        String usename=remoteDir.substring(index,end);
        index=end+1;
        end=remoteDir.lastIndexOf("@");
        String password=remoteDir.substring(index,end);
        index=end+1;
        end=remoteDir.indexOf("/",end);
        String ip=remoteDir.substring(index,end);
        String remoteurl="smb://"+ip+"/"+remoteDir.substring(end+1);
        NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(ip, usename, password);
        InputStream in = null;
        try {
            String trgFilePath = StringHelper.trimEndFileSp(remoteurl)+"/" + pFileName;
            SmbFile remoteFile = new SmbFile(trgFilePath,auth);
            if (!remoteFile.exists()) {
                pSb.append("远程文件"+trgFilePath+"不存在");
                return remoteFileText;
            }
            Long filelength = remoteFile.length();
            byte[] filecontent = new byte[filelength.intValue()];
            in = new SmbFileInputStream(remoteFile);
            in.read(filecontent);
            remoteFileText = new String(filecontent, charset);
        } catch (Exception e) {
            e.printStackTrace();
            pSb.append("内容获取异常："+e.getMessage());
        } finally {
            try {
                if (null != in) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
                pSb.append("IO流关闭异常："+e.getMessage());
            }
        }
        return remoteFileText;
    }

    public static void main(String[] args) {
        try {
        	StringBuilder smbSb = new StringBuilder();
            //smbDownload("D:/temp//", "smb://pub:fingard1!@10.60.44.98/数据库脚本/2.3.0/", "371-388.sql", smbSb);
            //smbUploading("D:/temp//1.txt", "", "smb://pub:fingard1!@10.60.44.98/数据库脚本/2.3.0/");
            //smbUploadingInChar("D:/textReq.txt","","smb://hp:3397687@LAPTOP-BJO4ES18/smbReceipt/");
            smbDownloadInChar("D:","smb://hp:339:7@6%$87@LAPTOP-BJO4ES18/smbReceipt/","textReq.txt",new StringBuilder());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
